home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************
-
- Author: Dale Roberts
- Date: 8/30/95
- Program: GIVEIO.SYS
- Compile: Use DDK BUILD facility
-
- Purpose: Give direct port I/O access to a user mode process.
-
- *********************************************************************/
- #include <ntddk.h>
-
- /*
- * The name of our device driver.
- */
- #define DEVICE_NAME_STRING L"giveio"
-
- /*
- * This is the "structure" of the IOPM. It is just a simple
- * character array of length 0x2000.
- *
- * This holds 8K * 8 bits -> 64K bits of the IOPM, which maps the
- * entire 64K I/O space of the x86 processor. Any 0 bits will give
- * access to the corresponding port for user mode processes. Any 1
- * bits will disallow I/O access to the corresponding port.
- */
- #define IOPM_SIZE 0x2000
- typedef UCHAR IOPM[IOPM_SIZE];
-
- /*
- * This will hold simply an array of 0's which will be copied
- * into our actual IOPM in the TSS by Ke386SetIoAccessMap().
- * The memory is allocated at driver load time.
- */
- IOPM *IOPM_local = 0;
-
- /*
- * These are the two undocumented calls that we will use to give
- * the calling process I/O access.
- *
- * Ke386IoSetAccessMap() copies the passed map to the TSS.
- *
- * Ke386IoSetAccessProcess() adjusts the IOPM offset pointer so that
- * the newly copied map is actually used. Otherwise, the IOPM offset
- * points beyond the end of the TSS segment limit, causing any I/O
- * access by the user mode process to generate an exception.
- */
- void Ke386SetIoAccessMap(int, IOPM *);
- void Ke386QueryIoAccessMap(int, IOPM *);
- void Ke386IoSetAccessProcess(PEPROCESS, int);
-
- /*********************************************************************
- Release any allocated objects.
- *********************************************************************/
- VOID GiveioUnload(IN PDRIVER_OBJECT DriverObject)
- {
- WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
- UNICODE_STRING uniDOSString;
-
- if(IOPM_local)
- MmFreeNonCachedMemory(IOPM_local, sizeof(IOPM));
-
- RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);
- IoDeleteSymbolicLink (&uniDOSString);
- IoDeleteDevice(DriverObject->DeviceObject);
- }
-
- /*********************************************************************
- Set the IOPM (I/O permission map) of the calling process so that it
- is given full I/O access. Our IOPM_local[] array is all zeros, so
- the IOPM will be all zeros. If OnFlag is 1, the process is given I/O
- access. If it is 0, access is removed.
- *********************************************************************/
- VOID SetIOPermissionMap(int OnFlag)
- {
- Ke386IoSetAccessProcess(PsGetCurrentProcess(), OnFlag);
- Ke386SetIoAccessMap(1, IOPM_local);
- }
-
- void GiveIO(void)
- {
- SetIOPermissionMap(1);
- }
-
- /*********************************************************************
- Service handler for a CreateFile() user mode call.
-
- This routine is entered in the driver object function call table by
- the DriverEntry() routine. When the user mode application calls
- CreateFile(), this routine gets called while still in the context of
- the user mode application, but with the CPL (the processor's Current
- Privelege Level) set to 0. This allows us to do kernel mode
- operations. GiveIO() is called to give the calling process I/O
- access. All the user mode application needs do to obtain I/O access
- is open this device with CreateFile(). No other operations are
- required.
- *********************************************************************/
- NTSTATUS GiveioCreateDispatch(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
- {
- GiveIO(); // give the calling process I/O access
-
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
- }
-
- /*********************************************************************
- Driver Entry routine.
-
- This routine is called only once after the driver is initially
- loaded into memory. It allocates everything necessary for the
- driver's operation. In our case, it allocates memory for our IOPM
- array, and creates a device which user mode applications can open.
- It also creates a symbolic link to the device driver. This allows
- a user mode application to access our driver using the \\.\giveio
- notation.
- *********************************************************************/
- NTSTATUS DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
- {
- PDEVICE_OBJECT deviceObject;
- NTSTATUS status;
- WCHAR NameBuffer[] = L"\\Device\\" DEVICE_NAME_STRING;
- WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
- UNICODE_STRING uniNameString, uniDOSString;
-
- //
- // Allocate a buffer for the local IOPM and zero it.
- //
- IOPM_local = MmAllocateNonCachedMemory(sizeof(IOPM));
- if(IOPM_local == 0)
- return STATUS_INSUFFICIENT_RESOURCES;
- RtlZeroMemory(IOPM_local, sizeof(IOPM));
-
- //
- // Set up device driver name and device object.
- //
- RtlInitUnicodeString(&uniNameString, NameBuffer);
- RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);
-
- status = IoCreateDevice(DriverObject, 0,
- &uniNameString,
- FILE_DEVICE_UNKNOWN,
- 0, FALSE, &deviceObject);
-
- if(!NT_SUCCESS(status))
- return status;
-
- status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);
-
- if (!NT_SUCCESS(status))
- return status;
-
- //
- // Initialize the Driver Object with driver's entry points.
- // All we require are the Create and Unload operations.
- //
- DriverObject->MajorFunction[IRP_MJ_CREATE] = GiveioCreateDispatch;
- DriverObject->DriverUnload = GiveioUnload;
- return STATUS_SUCCESS;
- }
-
-